/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * httpd
 * Copyright (C) Dnyanesh Gate 2012 <dnyaneshgate@yahoo.com>
 * 
 * httpd is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * httpd is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <Http.h>

char buffer[BUFFSIZE];
FILE *fp = NULL;
FILE *page = NULL;

int Http::Init(){
	noOfClients = 0;
	SERVER = new ServerSocket ();
	if(SERVER->Bind(PORT) == SUCCESS){
		if(SERVER->Listen() == SUCCESS){
			memset(t,-1,MAXCLIENTS);
			printf("Server Initialised Successfully...\n");
			return SUCCESS;
		}
	}
	return ERROR;
}

void Http::Start(){
	while(1){
		if(noOfClients >= MAXCLIENTS)
			break;
		Listen();
	}
}

void Http::End(){
	delete SERVER;
}

void Http::Listen(){
#ifdef DEBUG
	printf("Listening...\n");
#endif
	int i = noOfClients;
	if(SERVER->Accept(i) == SUCCESS){
		t[i].Run(getRequest,&i);
		sleep(1);
		noOfClients++;
	}
}

void* Http::getRequest(void *data){
	char absPath[1024];
	char *method, *proto, *path;
	struct stat buf;
	Http *self = Http::getInstance();
	int i = *((int*)data);

#ifdef DEBUG
	printf("New Thread Started: %d\n",i);
#endif
	bzero(buffer,BUFFSIZE);
	(self->SERVER)->Recv(buffer,i);
	//std::cout<<"REQUEST:\n"<<buffer<<std::endl;
	method = strtok(buffer," ");
	path = strtok(NULL," ");
	proto = strtok(NULL,"\r");

	if(!strcmp(method,GET_METHOD)){
		if(!strcmp(path,"/")){
			sprintf(absPath,"%s%s",DEFAULT_DIR,"/index.html");
		}
		else{
			sprintf(absPath,"%s%s",DEFAULT_DIR,path);
		}
		printf("path : %s\n",absPath);
		if(stat(absPath,&buf) == -1){
			self->SendError(403,"Forbidden","Access Denied",i);
		}
		else{
			self->SendFileData(absPath, &buf, i);
		}
	}
	else{
		self->SendError(501,"Not Supported","Method Not Supported",i);
	}
#ifdef DEBUG
	printf("Thread End: %d\n",i);
#endif
	(self->SERVER)->CloseConnection(i);
	self->t[i].Exit();
	//self->t[i] = NULL;
	return NULL;
}

const char* Http::getMimeType(const char* file){
	const char *ext = strrchr(file,'.');
	if(!strcmp(ext, ".html") || !strcmp(ext, ".htm"))		return "text/html";
	if(!strcmp(ext, ".jpg") || !strcmp(ext, ".jpeg"))		return "image/jpeg";
	if(!strcmp(ext, ".gif"))								return "image/gif";
	if(!strcmp(ext, ".png"))								return "image/png";
	if(!strcmp(ext, ".css"))								return "text/css";
	if(!strcmp(ext, ".au"))									return "audio/basic";
	if(!strcmp(ext, ".wav"))								return "audio/wav";
	if(!strcmp(ext, ".avi"))								return "video/x-msvideo";
	if(!strcmp(ext, ".mpeg") || !strcmp(ext, ".mpg"))		return "video/mpeg";
	if(!strcmp(ext, ".mp3"))								return "audio/mpeg";
	return "text/html";
}

void Http::SendHeader(int status, const char* title, const char* mime_t, int length, int i){
	time_t now;
	char response[2000];
	char buf[128];
	bzero(buf,128);
	now = time(NULL);
/*	Date: Fri, 31 Dec 1999 23:59:59 GMT		*/
	strftime(buf,sizeof buf,"%a, %d %b %Y %T GMT",gmtime(&now));
	bzero(response,2000);
	sprintf(response,"%s %d %s\nDate: %s\nContent-Type: %s\nContent-Length: %d\n\n",PROTOCOL,status,title,buf,mime_t,length);
	printf("RESPONSE:\n%s\n",response);
	SERVER->Send(response,strlen(response),i);
}

void Http::SendError(int status, const char* title, const char* text,int i){
	char buf[BUFFSIZE];
	bzero(buf,BUFFSIZE);
	sprintf(buf,"<html>\n\
					<title>%d %s</title>\n\
					<body>\n\
						<h3>%d %s</h3>\n\
						<h1>%s</h1>\n\
					</body>\n\
				</html>\n",status,title,status,title,text);
	SendHeader(status,title,"text/html",strlen(buf),i);
	SERVER->Send(buf,strlen(buf),i);
}

void Http::SendFileData(const char *path, struct stat *statBuf, int i){
	int n=0;
	fp = fopen(path,"rb");
	if(fp == NULL){
		SendError(403,"Forbidden","Access Denied",i);
		return;
	}
	int len = statBuf->st_size;
	SendHeader(200,"OK",getMimeType(path),len,i);
	bzero(buffer,BUFFSIZE);
	while((n=fread(buffer,1,sizeof buffer,fp)) > 0){
		//printf("%s\n",buffer);
		SERVER->Send(buffer,n,i);
	}
	fclose(fp);
	fp = NULL;
}